"""
Copyright 2008 Olivier Belanger

This file is part of Ounk.

Ounk is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Ounk is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Ounk.  If not, see <http://www.gnu.org/licenses/>.
"""

import threading, time, random

class RhythmPattern(threading.Thread):
    """Generate a rythm taps table for use with sequencer

size = 16 # number of beats per bar
weight1 = 90 # 0 -> 100
weight2 = 60 # 0 -> 100
weight3 = 20 # 0 -> 100

return RhythmPattern object"""

    def __init__(self, time, function, size=16, weight1=90, weight2=60, weight3=20):
        threading.Thread.__init__(self)
        self.t = time
        self.currentTime = 0
        self.function = function
        self.terminated = False
        self.next = 0
        self.count = 1
        self.ok = False
        self.bar = 0
        self.size = size
        self.seq = [0 for i in range(size)]
        self.amplitude = 0
        self._setTable(size, weight1, weight2, weight3)

    def run(self):
        while not self.terminated:
            if self.ok:
                if self.seq[self.count-1] != 0:
                    self.function(self.seq[self.count-1])
                self.count += 1
                if self.count > self.size:
                    self.count = 1
                    self.bar += 1
            self.currentTime += self.t              
            time.sleep(self.t)
        print "thread terminated"    
            
    def _setTable(self, size, weight1, weight2, weight3):
        prob = [0 for i in range(size)]
        self.seq = [0 for i in range(size)]
        if size % 7 == 0:
            beat = 7
            for i in range(size):
                if i % beat == 4 or i % beat == 2:
                    prob[i] = (weight2, .75)
                elif i % beat == 0:
                    prob[i] = (weight1, 1)
                else:
                    prob[i] = (weight3, .5)
        elif size % 6 == 0:
            beat = 6
            for i in range(size):
                if i % beat == 3:
                    prob[i] = (weight2, .75)
                elif i % beat == 0:
                    prob[i] = (weight1, 1)
                else:
                    prob[i] = (weight3, .5)
        elif size % 5 == 0:
            beat = 5
            for i in range(size):
                if i % beat == 3:
                    prob[i] = (weight2, .75)
                elif i % beat == 0:
                    prob[i] = (weight1, 1)
                else:
                    prob[i] = (weight3, .5)
        elif size % 4 == 0:
            beat = 4
            for i in range(size):
                if i % beat == 2:
                    prob[i] = (weight2, .75)
                elif i % beat == 0:
                    prob[i] = (weight1, 1)
                else:
                    prob[i] = (weight3, .5)
        elif size % 3 == 0:
            beat = 3
            for i in range(size):
                if i % beat == 0:
                    prob[i] = (weight1, 1)
                else:
                    prob[i] = (weight3, .5)
        elif size % 2 == 0:
            beat = 2
            for i in range(size):
                if i % beat == 0:
                    prob[i] = (weight1, 1)
                else:
                    prob[i] = (weight3, .5)

        for i in range(size):
            if random.randint(0, 100) < prob[i][0]:
                self.seq[i] = prob[i][1]
            else:
                self.seq[i] = 0
        print self.seq

    def play(self, state=True):
        self.ok = state
        
    def getStepValue(self, step):
        return self.seq[step-1]

    def regenerate(self, size=16, weight1=90, weight2=60, weight3=20):
        """Regenerate a new algorithmic rhythm sequence based on new weights.
        
size = 16
weight1 = 90
weight2 = 60
weight3 = 20

--- PARAMETERS ---

size : Length, in number of steps, of the new generated sequence.
weight1 : Percentage chance of primary beats to be chosen.
weight2 : Percentage chance of secondary beats to be chosen.
weight3 : Percentage chance of weak beats to be chosen.
"""
        self._setTable(size, weight1, weight2, weight3)

    def changeTime(self, time):
        """Change time interval of a pattern objet
     
time = time_interval_secs
"""
        self.t = time

    def getBeat(self):
        """Returns the current beat of the pattern."""
        return self.count

    def getBar(self):
        """Return the current bar of the pattern."""
        return self.bar
        
    def getTime(self):
        """Returns the current time of the pattern."""
        return self.currentTime
        
    def stop(self):
        self.terminated = True